package com.justgame.project.cloud.common.query;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.justgame.project.cloud.common.util.ArrayUtils;
import com.justgame.project.cloud.common.util.MapBuilder;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;

import java.util.*;
import java.util.stream.Collectors;

@Getter
@Setter(value = AccessLevel.PACKAGE)
@SuppressWarnings("all")
public class Query {
    private String aliasPrefix;
    /* 当前数据表实例类型 */
    private final Class currentTableClass;
    /* 当前数据表需要查询的字段 */
    private String[] currentTableSelectColumns;
    /* 关联条件（左条件） */
    private final SFunction leftOn;
    /* 关联条件（右条件） */
    private final SFunction rightOn;
    /* 查询的字段数据返回到结果映射对象的字段名 */
    private final String mappingFieldName;
    /* 关联其他数据表 */
    private List<Query> joinQueries;
    /* 当前所属SQL语句环境中主表实例类型 */
    private Class masterTableClass;
    /* 主表查询节点 */
    private Query master;
    /* 当前数据表的父查询节点 */
    private Query parent;


    private Query(Class currentTableClass, List<Query> joinQueries, String[] currentTableSelectColumns, SFunction leftOn, SFunction rightOn,String mappingFieldName) {
        this.currentTableClass = currentTableClass;
        this.joinQueries = joinQueries;
        this.currentTableSelectColumns = currentTableSelectColumns;
        this.leftOn = leftOn;
        this.rightOn = rightOn;
        this.mappingFieldName = mappingFieldName;
    }

    public boolean isMaster(){
        if (Objects.isNull(master)){
            return currentTableClass.equals(masterTableClass);
        }
        return Objects.equals(this,master);
    }

    public static QueryBuilder builder(Class tableClass){
        return new QueryBuilder(tableClass);
    }

    public Query joins(Query... joinQueries){
        this.joinQueries = Arrays.asList(joinQueries);
        return this;
    }

    public static Map<Class, Query> merge(List<Query> queryList){
        return MapBuilder.<Class, Query>builder()
                .merge(
                        queryList.stream()
                                .map(column -> MapBuilder.<Class, Query>builder(1)
                                        .put(column.currentTableClass, column)
                                        .build())
                                .collect(Collectors.toList()))
                .build();
    }

    public static class QueryBuilder {
        private final Class tableClass;
        /**
         * 查询的字段数据返回到结果映射对象的字段名
         */
        private String mappingName;
        private SFunction left;
        private SFunction right;
        private String[] selectColumns = {StringPool.ASTERISK};
        private List<Query> joinQueries;

        private QueryBuilder(Class tableClass) {
            this.tableClass = tableClass;
        }

        public QueryBuilder selectColumns(String... selectColumns){
            if (ArrayUtils.notEmpty(selectColumns)){
                this.selectColumns = selectColumns;
            }
            return this;
        }

        public QueryBuilder selectColumns(Column column){
            Optional<String[]> columnOpt = Optional.ofNullable(column).map(Column::getColumns);
            if (columnOpt.isPresent()){
                this.selectColumns = columnOpt.get();
            }
            return this;
        }

        public QueryBuilder mapping(String mappingName){
            this.mappingName = mappingName;
            return this;
        }

        public QueryBuilder leftOn(SFunction left){
            this.left = left;
            return this;
        }

        public QueryBuilder rightOn(SFunction right){
            this.right = right;
            return this;
        }

        public QueryBuilder join(Query... joinQueries){
            if (ArrayUtils.notEmpty(joinQueries)){
                this.joinQueries = Arrays.stream(joinQueries).peek(col -> col.masterTableClass = tableClass).collect(Collectors.toList());
            }
            return this;
        }

        public Query build(){
            return new Query(
                    tableClass,
                    joinQueries,
                    selectColumns,
                    left,
                    right,
                    mappingName
            );
        }
    }

    public static interface QueryHandler{
        void handle(Query query);
        int sort();
    }
}
